{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TwoPortOnePath, EnhancedResponse, and FakeFlip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Intro"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This example demonstrates a macgyver-ish  shortcut you can take if you are measuring a  device that is ** reciprocal** and  **symmetric**  on a switch-less three-receiver system. For more information about error correction this type of architecture, see  [Calibration With Three Receivers](Calibration With Three Receivers.ipynb).\n",
    "\n",
    "In general, full error correction of a 2-port network on a switchless three-receiver architecture requires each DUT to measured in two orientations.  However, if the DUT is known to be reciprocal ($S_{21}=S_{12}$) and symmetric ($S_{11}=S_{22}$),  then measurements in both orientations produce the same response, and therefore  are unnecesary.\n",
    "\n",
    "The following worked example compares the corrected response of a 10dB attenuator at WR-12 as corrected using  full error correction and psuedo-full error correction using:\n",
    "\n",
    "1. Full Correction\n",
    "2. Psuedo-Full Correction (FakeFlip)\n",
    "3. Partial  (EnhancedResponse)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from IPython.display import *\n",
    "Image('three_receiver_cal/pics/macgyver.jpg', width='50%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These   measurements where taken on a Agilent PNAX with a set of VDI WR-12 TXRX-RX Frequency Extender heads. The measurements of the calibration standards and DUT's  were downloaded from the VNA by saving touchstone files of the raw s-parameter data to disk.  \n",
    "\n",
    "In the code that follows a TwoPortOnePath calibration is created from corresponding  measured and ideal responses of the calibration standards. The measured networks are read from disk, while their corresponding ideal responses are generated using scikit-rf. More information about using scikit-rf to do offline calibrations can be found [here](http://scikit-rf.readthedocs.org/en/latest/tutorials/calibration.html). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import skrf as rf \n",
    "%matplotlib inline\n",
    "from pylab import * \n",
    "rf.stylely()\n",
    "\n",
    "from skrf.calibration import TwoPortOnePath\n",
    "from skrf.media import RectangularWaveguide\n",
    "from skrf import two_port_reflect as tpr\n",
    "from skrf import  mil\n",
    "\n",
    "\n",
    "raw = rf.read_all_networks('three_receiver_cal/data/')\n",
    "\n",
    "\n",
    "\n",
    "# pull frequency information from measurements\n",
    "frequency = raw['short'].frequency\n",
    "\n",
    "# the media object \n",
    "wg = RectangularWaveguide(frequency=frequency, a=120*mil, z0=50)\n",
    "\n",
    "# list of 'ideal' responses of the calibration standards\n",
    "ideals = [wg.short(nports=2),\n",
    "          tpr(wg.delay_short( 90,'deg'), wg.match()),\n",
    "          wg.match(nports=2),\n",
    "          wg.thru()]\n",
    "\n",
    "# corresponding measurments to the 'ideals'\n",
    "measured = [raw['short'],\n",
    "            raw['quarter wave delay short'],\n",
    "            raw['load'],\n",
    "            raw['thru']]\n",
    "\n",
    "# the Calibration object\n",
    "cal = TwoPortOnePath(measured = measured, ideals = ideals )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Correction Options"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With the calibration created above, we compare the corrected response of WR-12 10dB attenuator using **Full**, **Psuedo-Full**,  and **Partial** Correction. Each correction algorithm is described below. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "Image('three_receiver_cal/pics/symmetric DUT.jpg', width='75%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Full Correction (TwoPortOnePath)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Full correction on this type of architecture has been called *TwoPortOnePath*. In `scikit-rf` using this correction algorithm requires the device to be measured  in both orientations, **forward** and **reverse**, and passing them both to the `apply_cal()` function as a `tuple`. Neglecting the connector uncertainty, this type of correction is identical to full two-port **SOLT** calibration."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Psuedo-full Correction ( FakeFlip)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we assume the DUT is **reciprocal** and **symmetric**, then measuring the device in both orientations will produce the same result. Therefore, the reverse orientation measurment may be replaced by a copy of the forward orientation measurement. We refer to this technique as the *Fake Flip*. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert \">\n",
    "**Warning**: \n",
    "Be sure that you understand the assumptions of reciprocity and symmetry before using this macgyver technique,  incorrect usage can lead to nonsense results.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Partial Correction (EnhancedResponse)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you pass a single measurement to the `apply_cal()` function, then the calibration will employ partial correction. This type of correction is known as `EnhancedResponse`. While the *Fake Flip* technique assumes  the device is reciprocal and symmetric, the `EnhancedResponse` algorithm *implicitly* assumes that the port 2 of the device is perfectly matched.  The accuracy of the corrected result produced with  either of these algorithms depends on accuracy of the assumptions. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "dutf = raw['attenuator (forward)']\n",
    "dutr = raw['attenuator (reverse)']\n",
    "\n",
    "\n",
    "# note the correction algorithm is different depending on what is passed to \n",
    "# apply_cal\n",
    "corrected_full =     cal.apply_cal((dutf, dutr)) \n",
    "corrected_fakeflip = cal.apply_cal((dutf,dutf)) \n",
    "corrected_partial =  cal.apply_cal(dutf) \n",
    "\n",
    "\n",
    "\n",
    "f, ax = subplots(2,2, figsize=(8,8))\n",
    "\n",
    "for m in [0,1]:\n",
    "    for n in [0,1]:\n",
    "        ax_ = ax[m,n]\n",
    "        ax_.set_title('$S_{%i%i}$'%(m+1,n+1))\n",
    "        corrected_full.plot_s_db(m,n, label='Full Correction',ax=ax_ )\n",
    "        corrected_fakeflip.plot_s_db(m,n, label='Psuedo-full Correction', ax=ax_)\n",
    "        if n==0:\n",
    "            corrected_partial.plot_s_db(m,n, label='Partial Correction', ax=ax_)\n",
    "\n",
    "\n",
    "tight_layout()"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [default]",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
